package com.barbarossa.vod.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class TorrentUtils {
	
    public static byte[] getBytesFromFile(File file) throws IOException {

        InputStream is = new FileInputStream(file);

        // Get the size of the file
        long length = file.length();
        System.out.println("DEBUG: Length of " + file + " is " + length + "\n");

        /*
         * You cannot create an array using a long type. It needs to be an int
         * type. Before converting to an int type, check to ensure that file is
         * not loarger than Integer.MAX_VALUE;
         */
        if (length > Integer.MAX_VALUE) {
            System.out.println("File is too large to process");
            return null;
        }

        // Create the byte array to hold the data
        byte[] bytes = new byte[(int)length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while ( (offset < bytes.length)
                &&
                ( (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) ) {

            offset += numRead;

        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }

        is.close();
        return bytes;
    }
    
	public static int indexOf(byte[] data, byte[] pattern) {
        int[] failure = computeFailure(pattern);

        int j = 0;
        if (data.length == 0) return -1;

        for (int i = 0; i < data.length; i++) {
            while (j > 0 && pattern[j] != data[i]) {
                j = failure[j - 1];
            }
            if (pattern[j] == data[i]) { j++; }
            if (j == pattern.length) {
                return i - pattern.length + 1;
            }
        }
        return -1;
    }
	
	private static int[] computeFailure(byte[] pattern) {
        int[] failure = new int[pattern.length];

        int j = 0;
        for (int i = 1; i < pattern.length; i++) {
            while (j > 0 && pattern[j] != pattern[i]) {
                j = failure[j - 1];
            }
            if (pattern[j] == pattern[i]) {
                j++;
            }
            failure[i] = j;
        }

        return failure;
    }
	
	public static String getTorrentHash(String fileName) {
		File f = new File(URI.create(fileName));
		
		if (!f.exists())
			return null;
		
		byte fileBuffer[];
		try {
			fileBuffer = getBytesFromFile(f);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		if (null == fileBuffer)
			return null;

		return getTorrentHash(fileBuffer);
	}
	
	public static String getTorrentHash(byte fileBuffer[]) {
		final String START_STR = "4:info";
		final String END_STR = "5:nodes";
		final char[] CHAR_TABLE = "0123456789ABCDEF".toCharArray();
		
		int start = indexOf(fileBuffer, START_STR.getBytes());
		if (start < 0)
			return null;
		int end = indexOf(fileBuffer, END_STR.getBytes());
		if (end < 0)
			return null;
		
		start += START_STR.length();
		
		MessageDigest sha1;
		try {
			sha1 = MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;					
		}
		sha1.update(fileBuffer, start, end - start);
		byte[] hash = sha1.digest();
		fileBuffer = null;
		
		StringBuffer sb = new StringBuffer(64);
		int unsignedByte = 0;
		for (int i = 0; i < hash.length; i++) {
			unsignedByte = 0xff & hash[i]; 
			sb.append(CHAR_TABLE[unsignedByte >> 4]);
			sb.append(CHAR_TABLE[unsignedByte & 0x0f]);
		}
		
		return sb.toString();
	}
		
}
